#include <gtk/gtk.h>
#include <assert.h>

#include "common.h"

/**
 * 说明：
 * GtkCellRenderer 就决定了在 GtkTreeViewColumn 中的数据究竟是如何来进行显示呈现的。
 * GtkListStore 和 GtkTreeStore 的功能为体现模型(model)的作用。
 * 也就是说他们是用来处理和分析将要在 GtkTreeView 显示的数据的。
 * GtkTreeIter 则是一个数据结构被用于在 GtkTreeView 构件中,对行中的数据进行操作。
 * GtkTreeSelection 则是用来处理选项的。
 */

enum { LIST_ITEM = 0, N_COLUMNS };

static void init_list(GtkWidget *list);
static void add_to_list(GtkWidget *list, const gchar *str);
void on_changed(GtkWidget *widget, gpointer label);
void simple_demo(GtkWidget *window);            /*简单列表示例*/

typedef struct _data_t data_t;
struct _data_t {
    GtkWidget *treeView;
    GtkWidget *entry;
    GtkTreeSelection *treeSelection;
};

static void append_item(GtkWidget *widget, gpointer data);
static void remove_item(GtkWidget *widget, gpointer data);
static void remove_all(GtkWidget *widget, gpointer data);
void advanced_demo(GtkWidget *window);          /*高级列表示例*/

enum { COLUMN = 0, NUM_COLS };
void on_treeSelection_changed(GtkWidget *widget, gpointer statusbar);
static GtkTreeModel *create_and_fill_model(void);
static GtkWidget *create_view_and__model(void);
void treeView_demo(GtkWidget *window);

int main( int argc, char *argv[]){
    GtkWidget *window;
    GdkColor  color_ = {0x0, 0x50, 0x50, 0x50};

    gtk_init(&argc, &argv);

    /* window */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
#if 0
    gtk_window_fullscreen(GTK_WINDOW(window));              /*设置全屏*/
#else
    gtk_widget_set_size_request (window, 750, 550);         /*设置窗口大小*/
    gtk_window_set_resizable(GTK_WINDOW(window), FALSE);    /*设置窗口不能拉伸*/
#endif
    gtk_window_set_title(GTK_WINDOW(window), TITLE);
    gtk_container_set_border_width(GTK_CONTAINER(window), 15);  /*设置容器边界大小*/
    gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color_); /*设置为背景颜色*/
//    gtk_window_set_decorated(GTK_WINDOW(window), FALSE);	/*设置不提供装饰*/

    /* test */
//    simple_demo(window);
//    advanced_demo(window);
    treeView_demo(window);

    /* signal setting */
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}

void treeView_demo(GtkWidget *window)
{
    GtkWidget *treeView;
    GtkWidget *vbox;
    GtkTreeSelection *treeSelection;
    GtkWidget *statusbar;


    treeView = create_view_and__model();

    treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView));

    statusbar = gtk_statusbar_new();

    vbox = gtk_vbox_new(FALSE, 2);
    gtk_container_add(GTK_CONTAINER(window), vbox);
    gtk_box_pack_start(GTK_BOX(vbox), treeView, TRUE, TRUE, 1);
    gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);

    g_signal_connect(treeSelection, "changed", G_CALLBACK(on_treeSelection_changed), statusbar);
}

GtkWidget *create_view_and__model()
{
    GtkTreeViewColumn *col;
    GtkCellRenderer *renderer;
    GtkWidget *view;
    GtkTreeModel *model;

    view = gtk_tree_view_new();

    col = gtk_tree_view_column_new();
    gtk_tree_view_column_set_title(col, "Programming Language");
    gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);

    renderer = gtk_cell_renderer_text_new();
    gtk_tree_view_column_pack_start(col, renderer, TRUE);
    gtk_tree_view_column_add_attribute(col, renderer, "text", COLUMN);

    model = create_and_fill_model();

    gtk_tree_view_set_model(GTK_TREE_VIEW(view), model);

    g_object_unref(model);

    return view;
}

GtkTreeModel *create_and_fill_model()
{
    GtkTreeStore *treeStore;
    GtkTreeIter toplevelTreeIter;
    GtkTreeIter childTreeIter;

    treeStore = gtk_tree_store_new(NUM_COLS, G_TYPE_STRING);    /*树型存储*/
    gtk_tree_store_append(treeStore, &toplevelTreeIter, NULL);
    gtk_tree_store_set(treeStore, &toplevelTreeIter, COLUMN, "Scripting Languages", -1);
    gtk_tree_store_append(treeStore, &childTreeIter, &toplevelTreeIter);
    gtk_tree_store_set(treeStore, &childTreeIter, COLUMN, "Python", -1);
    gtk_tree_store_append(treeStore, &childTreeIter, &toplevelTreeIter);
    gtk_tree_store_set(treeStore, &childTreeIter, COLUMN, "Perl", -1);
    gtk_tree_store_append(treeStore, &childTreeIter, &toplevelTreeIter);
    gtk_tree_store_set(treeStore, &childTreeIter, COLUMN, "PHP", -1);

    gtk_tree_store_append(treeStore, &toplevelTreeIter, NULL);
    gtk_tree_store_set(treeStore, &toplevelTreeIter, COLUMN, "Compiled Languages", -1);
    gtk_tree_store_append(treeStore, &childTreeIter, &toplevelTreeIter);
    gtk_tree_store_set(treeStore, &childTreeIter, COLUMN, "C", -1);
    gtk_tree_store_append(treeStore, &childTreeIter, &toplevelTreeIter);
    gtk_tree_store_set(treeStore, &childTreeIter, COLUMN, "C++", -1);
    gtk_tree_store_append(treeStore, &childTreeIter, &toplevelTreeIter);
    gtk_tree_store_set(treeStore, &childTreeIter, COLUMN, "Java", -1);

    return GTK_TREE_MODEL(treeStore);
}

void on_treeSelection_changed(GtkWidget *widget, gpointer statusbar)
{
    GtkTreeIter iter;
    GtkTreeModel *model;
    char *value;

    if (gtk_tree_selection_get_selected(GTK_TREE_SELECTION(widget), &model, &iter)) {
        gtk_tree_model_get(model, &iter, COLUMN, &value, -1);
        gtk_statusbar_push(GTK_STATUSBAR(statusbar), gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar),value), value);
        g_free(value);
    }
}

void advanced_demo(GtkWidget *window)
{
    GtkWidget *treeView;
    GtkWidget *sw;
    GtkWidget *removeButton;
    GtkWidget *removerAllButton;
    GtkWidget *addButton;
    GtkWidget *entry;
    GtkWidget *vbox;
    GtkWidget *hbox;
    data_t *data;

    GtkTreeSelection *treeSelection;

    treeView = gtk_tree_view_new();
    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeView), FALSE);

    /* scroll window 滑块窗口 */
    sw = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
    gtk_container_add(GTK_CONTAINER(sw), treeView);

    addButton = gtk_button_new_with_label("Add");
    removeButton = gtk_button_new_with_label("Remove");
    removerAllButton = gtk_button_new_with_label("Remove All");
    entry = gtk_entry_new();

    hbox = gtk_hbox_new(TRUE, 0);
    gtk_box_pack_start(GTK_BOX(hbox), addButton, FALSE, FALSE, 3);
    gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 3);
    gtk_box_pack_start(GTK_BOX(hbox), removeButton, FALSE, FALSE, 3);
    gtk_box_pack_start(GTK_BOX(hbox), removerAllButton, FALSE, FALSE, 3);

    vbox = gtk_vbox_new(FALSE, 0);
    gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 5);
    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
    gtk_container_add(GTK_CONTAINER(window), vbox);

    init_list(treeView);

    treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView));

    data = (data_t *)g_malloc(sizeof(data_t));
    data->treeView = treeView;
    data->entry = entry;
    data->treeSelection = treeSelection;

    g_signal_connect(G_OBJECT(addButton), "clicked", G_CALLBACK(append_item), data);
    g_signal_connect(G_OBJECT(removeButton), "clicked", G_CALLBACK(remove_item), data);
    g_signal_connect(G_OBJECT(removerAllButton), "clicked", G_CALLBACK(remove_all), data);
}

void remove_all(GtkWidget *widget, gpointer data)
{
    GtkListStore *listStore;
    GtkTreeModel *treeModel;
    GtkTreeIter treeIter;
    GtkWidget *treeView = ((data_t *)data)->treeView;

    treeModel = gtk_tree_view_get_model(GTK_TREE_VIEW(treeView));
    listStore = GTK_LIST_STORE(treeModel);

    if (!gtk_tree_model_get_iter_first(treeModel, &treeIter)) {
        return;
    }
    gtk_list_store_clear(listStore);
}

void remove_item(GtkWidget *widget, gpointer data)
{
    GtkListStore *listStore;
    GtkTreeModel *treeModel;
    GtkTreeIter treeIter;
    GtkWidget *treeView = ((data_t *)data)->treeView;
    GtkTreeSelection *selection = ((data_t *)data)->treeSelection;

    treeModel = gtk_tree_view_get_model(GTK_TREE_VIEW(treeView));
    listStore = GTK_LIST_STORE(treeModel);

    if ( ! gtk_tree_model_get_iter_first(treeModel, &treeIter) ) {
        return;
    }

    if (gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection), &treeModel, &treeIter)) {
        gtk_list_store_remove(listStore, &treeIter);
    }
}

void append_item(GtkWidget *widget, gpointer data)
{
    GtkListStore *listStore;
    GtkTreeIter treeIter;
    GtkWidget *treeView = ((data_t *)data)->treeView;
    const char *str = gtk_entry_get_text(GTK_ENTRY(((data_t *)data)->entry));

    listStore = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(treeView)));

    gtk_list_store_append(listStore, &treeIter);
    gtk_list_store_set(listStore, &treeIter, LIST_ITEM, str, -1);
}

static void init_list(GtkWidget *list)
{
    GtkCellRenderer *renderer;
    GtkTreeViewColumn *column;
    GtkListStore *listStore;

    renderer = gtk_cell_renderer_text_new();

    column = gtk_tree_view_column_new_with_attributes("List Items", renderer, "text", LIST_ITEM, NULL); /*创建一列*/

    gtk_tree_view_append_column(GTK_TREE_VIEW(list), column); /*将列追加到表中*/

    listStore = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING);

    gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(listStore));

    g_object_unref(listStore);
}

static void add_to_list(GtkWidget *list, const gchar *str)
{
    GtkListStore *listStore;
    GtkTreeIter iter;

    listStore = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));

    gtk_list_store_append(listStore, &iter);
    gtk_list_store_set(listStore, &iter, LIST_ITEM, str, -1);
}

void on_changed(GtkWidget *widget, gpointer label)
{
    GtkTreeIter iter;
    GtkTreeModel *model;
    gchar *value;

    if (gtk_tree_selection_get_selected(GTK_TREE_SELECTION(widget), &model, &iter)) {
        gtk_tree_model_get(model, &iter, LIST_ITEM, &value, -1);
        gtk_label_set_text(GTK_LABEL(label), value);
        g_free(value);
    }
}

void simple_demo(GtkWidget *window)
{
    GtkWidget *vbox;
    GtkWidget *label;
    GtkWidget *treeView;
    GtkTreeSelection *treeSelection;

    treeView = gtk_tree_view_new();
    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeView), FALSE);  /*不显示列名称*/

    vbox = gtk_vbox_new(FALSE, 0);
    gtk_box_pack_start(GTK_BOX(vbox), treeView, TRUE, TRUE, 5);

    label = gtk_label_new("");
    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);

    gtk_container_add(GTK_CONTAINER(window), vbox);

    init_list(treeView);
    add_to_list(treeView, "Jake");
    add_to_list(treeView, "Peter");
    add_to_list(treeView, "Lucy");
    add_to_list(treeView, "Leon Adson LL");
    add_to_list(treeView, "Tom Ryan");

    treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView));
    g_signal_connect(treeSelection, "changed", G_CALLBACK(on_changed), label);
}
